package com.observable.test2;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * Created with IntelliJ IDEA.
 * Description:
 *
 * @author lzy
 * @date 2020-09-03 下午3:38
 */
public class EventListener {
    // JDK底层的Listener通常也是这样来设计的
    protected Map<String, Event> events = new HashMap<>();

    /**
     * 首字符转换为大写
     * To upper first case string.
     *
     * @param str the str
     * @return the string
     */
    private static String toUpperFirstCase(String str) {
        char[] chars = str.toCharArray();
        chars[0] -= 32;
        return String.valueOf(chars);
    }

    /**
     * 通过事件名称和一个目标对象来触发事件
     * Add listener.
     *
     * @param eventType the event type
     * @param target    the target
     */
    public void addListener(String eventType, Object target) {
        try {
            this.addListener(eventType, target, target.getClass().getMethod("on" + toUpperFirstCase(eventType), Event.class));
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    public void addListener(String eventType, Object target, Method callback) {
        // 注册事件
        events.put(eventType, new Event(target, callback));
    }

    /**
     * 触发，只要有动作就触发
     * Trigger.
     *
     * @param event the event
     */
    private void trigger(Event event) {
        event.setSource(this);
        event.setTime(System.currentTimeMillis());

        if (Objects.nonNull(event.getCallback())) {
            try {
                event.getCallback().invoke(event.getTarget(), event);
            } catch (IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 事件名称触发
     * Trigger.
     *
     * @param trigger the trigger
     */
    protected void trigger(String trigger) {
        if (!this.events.containsKey(trigger)) {
            return;
        }

        trigger(this.events.get(trigger).setTrigger(trigger));
    }
}
